import { arrayMethods } from "./array";
import Dep from "./dep";

export function observe(data) {
  

  // 在 JavaScript中，数组被认为是一种特殊的对象类型，并被实现成一个可索引的属性集合，
  // 其中每个属性的键为非负整数，值可以是任何类型的 JavaScript 值。由于在 JavaScript
  // 中的对象是通过引用来传递的，因此数组类型也被视为对象类型，因此使用 typeof 来判断数组时仍然会返回 object。
  if (typeof data != "object" || data == null) {
    return data;
  }
  let ob;
  ob = new Observer(data);

  return ob;
}

export class Observer {
  constructor(value) {
    this.dep = new Dep() // 给数组的所有对象都增加一个dep
    // 在当前的每个数据里面都加上__ob__
    Object.defineProperty(value, "__ob__", {
      enumerable: false, //不能进行枚举 也就是说它不会出现在 for...in 循环中
      value: this,
      writable: true,
      // configurable: true,
    });
    this.value = value;
    if (Array.isArray(value)) {
      // 重写数组的__proto__后进行覆盖
      value.__proto__ = arrayMethods;
      // 对数组中的里面所有数据进行监听
      this.observeArray(value);
    } else {
      this.walk(value);
    }
  }
  walk(obj) {
    // 因为Object.defineProperty 只能对单个对象进行监听 所以要使用循环进行遍历
    const keys = Object.keys(obj);
    for (let i = 0; i < keys.length; i++) {
      let key = keys[i];
      let value = obj[key];
      defineReactive(obj, key, value);
    }
  }
  observeArray(items) {
    for (let index = 0; index < items.length; index++) {
      observe(items[index]);
    }
  }
}
// 对 对象中的属性进行劫持
export function defineReactive(data, key, val) {
  // 递归 有性能问题 如果层次太多
  let childDep = observe(val);
  let dep = new Dep()
  Object.defineProperty(data, key, {
    get() {
      // 每次进行获取当前数据的时候进行收集依赖
       if(Dep.target){
        dep.depend()
        if(childDep.dep){
          childDep.dep.depend()
        }
       }
      // console.log("新值改变", val);
      return val;
    },
    set(newVal) {
      // console.log("newVal", newVal, val);
      if (newVal === val || (newVal !== newVal && value !== val)) {
        return;
      }
      // 每次的重新赋值后 新值都会失去响应式 所以在这进行重新赋值
      observe(newVal);
      val = newVal;
      // 更新
      dep.notify()
    },
  });
}
